//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Windows.Controls;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using System.Windows.Media;
    using System.Windows.Shapes;
    using Microsoft.Research.eResearch.Common.Eventing;

    public class IFElseUIElement : TridentUIActivityElement, ICompositeUIElement
    {
        /// <summary>
        /// The offset between the ChildElements collection and the MainContentHolder's children collection.
        /// This is due to the insertion of start element.
        /// </summary>
        private readonly int MetaUiElementsOffset = 1;

        /// <summary>
        /// Connects the 2 parallel activities on the left.
        /// </summary>
        private Polyline lineLeft;

        /// <summary>
        /// Connects the 2 parallel activities on the right.
        /// </summary>
        private Polyline lineRight;

        /// <summary>
        /// 
        /// </summary>
        private System.Windows.Media.Brush borderColor = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFC6D3D8"));

        /// <summary>
        /// The children of this composite element.
        /// </summary>
        private ObservableCollection<ITridentUIElement> childElements = new ObservableCollection<ITridentUIElement>();

        private IfElseActivityCompositeModel ifElseModel;

        /// <summary>
        /// Holds the main content.
        /// </summary>
        private StackPanel stkMainContentHolder;

        private ConditionConnector conditionConnector;

        /// <summary>
        /// The stack header.
        /// </summary>
        private WorkflowStackHeader header;

        /// <summary>
        /// Occurs when update is clicked.
        /// </summary>
        public override event EventHandler<ModelEventArgs> UpdateClick;

        public IFElseUIElement(IfElseActivityCompositeModel model, Dictionary<String, DataTypeModel> activityDataTypes)
            : base(model, activityDataTypes)
        {
            this.ifElseModel = model;
            if (!string.IsNullOrEmpty(model.UniqueId))
            {
                this.Name = model.UniqueId + "Element";
            }
            this.Loaded += new RoutedEventHandler(IFElseUIElement_Loaded);
            this.InitializeComponent();
        }
        void IFElseUIElement_Loaded(object sender, RoutedEventArgs e)
        {
            if (this.ComposerCtrl != null && this.ComposerCtrl.ConditionStore != null)
            {
                this.ComposerCtrl.ConditionStore.AddConditionalConnector(this.conditionConnector);
            }
        }

        /// <summary>
        /// Intialize the required component
        /// </summary>
        public new void InitializeComponent()
        {
            base.InitializeComponent();

            // Add the border which will contain the composite activity.
            this.MainBorder = new Border();
            this.MainBorder.VerticalAlignment = VerticalAlignment.Top;
            this.MainBorder.BorderBrush = this.borderColor;
            this.MainBorder.BorderThickness = new Thickness(1, 1, 2, 2);
            this.MainBorder.CornerRadius = new CornerRadius(7, 7, 7, 7);

            // Make the UIElement to be focusable.
            // this is used when we select a Binding and hit delete button.
            this.MainBorder.Focusable = true;

            // The background of the container is set to make it selectable.
            // if you have not set any background to any WPF control it will not raise any mouse down events.
            // This is by design of the controls in WPF.
            this.MainBorder.Background = Brushes.Transparent;

            StackPanel compositeActivityHolder = new StackPanel();

            // The header of the Ui element.
            this.header = new WorkflowStackHeader(false, this.Model);
            this.header.UpdateClick += delegate(object sender, ModelEventArgs args) { this.UpdateClick.Fire(sender, args); };
            ImageSourceConverter converter = new ImageSourceConverter();
            this.header.HeaderImage = (ImageSource)converter.ConvertFromString(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ScientificWorkflow/SeqActivity.png");
            this.header.HeaderBackground = Brushes.AliceBlue;
            this.header.HeaderText = Model.Label ?? Model.Name;
            
            // Set the left and right connectors for the activity.
            this.LeftControlFlowConnectionElement = this.header.LeftControlFlowConnectionElement;
            this.RightControlFlowConnectionElement = this.header.RightControlFlowConnectionElement;

            compositeActivityHolder.Children.Add(this.header);
            // ifelsePanel.Children.Add(this.header);

            // The body of the Element.
            Grid activityBody = new Grid();
            activityBody.MinHeight = 50;

            ColumnDefinition colLeftBranch = new ColumnDefinition();
            colLeftBranch.Width = new GridLength(20, GridUnitType.Auto);
            ColumnDefinition colMainContentHolder = new ColumnDefinition();
            colMainContentHolder.Width = new GridLength(1, GridUnitType.Auto);
            ColumnDefinition colRightBranch = new ColumnDefinition();
            colRightBranch.Width = new GridLength(20, GridUnitType.Star);

            activityBody.ColumnDefinitions.Add(colLeftBranch);
            activityBody.ColumnDefinitions.Add(colMainContentHolder);
            activityBody.ColumnDefinitions.Add(colRightBranch);

            this.lineLeft = new Polyline();
            activityBody.Children.Add(this.lineLeft);
            this.stkMainContentHolder = new StackPanel();
            activityBody.Children.Add(stkMainContentHolder);
            this.lineRight = new Polyline();
            activityBody.Children.Add(this.lineRight);

            Grid.SetColumn(this.lineLeft, 0);
            Grid.SetColumn(stkMainContentHolder, 1);
            Grid.SetColumn(this.lineRight, 2);

            // The lines for the paralell activity.
            this.lineLeft.Stroke = this.borderColor;
            this.lineLeft.StrokeThickness = 1.5;
            this.lineRight.Stroke = this.borderColor;
            this.lineRight.StrokeThickness = 1.5;

            this.stkMainContentHolder.Orientation = Orientation.Horizontal;

            this.lineLeft.Visibility = Visibility.Collapsed;
            this.lineLeft.HorizontalAlignment = HorizontalAlignment.Right;
            this.lineRight.Visibility = Visibility.Collapsed;
            this.lineRight.HorizontalAlignment = HorizontalAlignment.Left;

            activityBody.Background = Brushes.Transparent;
            activityBody.Margin = new Thickness(5);

            compositeActivityHolder.Children.Add(activityBody);
            this.MainBorder.Child = compositeActivityHolder;
            this.contentHolder.Children.Add(this.MainBorder);
        }

        #region Commented

        ///// <summary>
        ///// Event Handler for Load
        ///// </summary>
        ///// <param name="sender">object</param>
        ///// <param name="e">RoutedEventArgs</param>
        //private void OnIfElseUIElementLoaded(object sender, RoutedEventArgs e)
        //{
        //    this.IntialiseUI();
        //}

        ///// <summary>
        ///// Invokes the Composer Method to draw the IFElse Model
        ///// </summary>
        //private void IntialiseUI()
        //{
        //    // Draws the UI Representaion for IFElse
        //    this.composerCtrl.UpdateForActivity(this.ifElseModel,
        //                                 base.MainContentHolder,
        //                                this.composerCtrl.CurrentWorkflowModel);
        //}

        ///// <summary>
        ///// Intialise the IFElse Activity Model
        ///// </summary>
        //private void IntialiseActivityModel()
        //{
        //    IntialiseIfConditionActivityModel();
        //    IntialiseIFBranchActivityModel();
        //}

        ///// <summary>
        ///// Intialise the Branch Activity Model
        ///// </summary>
        //private void IntialiseIFBranchActivityModel()
        //{
        //    ActivityMetadata branchActivityMetadata = activityComposer.GetMetadata(UIDesignerCodeConstants.ACTIVITYCLASSPARALLEL);
        //    if (branchActivityMetadata != null)
        //    {
        //        // Add Branch Activity
        //        ActivityModel branchActivity = new ActivityModel(branchActivityMetadata, ComposerRenderer.UniqueCounter.ToString(CultureInfo.CurrentCulture));
        //        branchActivity.Label = "Branch";
        //        branchActivity.DeleteBehavior = ActivityDeleteBehavior.DeleteInvalid;
        //        branchActivity.CurrentParameterBindingVisibilty = this.ifElseModel.CurrentParameterBindingVisibilty;

        //        // Adding sequence activity as parallel activity First Child
        //        IntialiseTrueBranchActivityModel(branchActivity);

        //        // Adding sequence activity as parallel activity Second Child
        //        IntialiseElseBranchActivityModel(branchActivity);
        //    }
        //}

        ///// <summary>
        ///// Intialises False Activity Model
        ///// </summary>
        ///// <param name="branchActivity"></param>
        //private void IntialiseElseBranchActivityModel(ActivityModel branchActivity)
        //{
        //    ActivityMetadata falseBranchActivityMetadata = activityComposer.GetMetadata(UIDesignerCodeConstants.ACTIVITYCLASSSEQUENCE);
        //    ActivityModel falseBranchActivity = new ActivityModel(falseBranchActivityMetadata, ComposerRenderer.UniqueCounter.ToString(CultureInfo.CurrentCulture));
        //    if (null != falseBranchActivity)
        //    {
        //        ActivityMetadata iffalseMetadata = activityComposer.GetMetadata(UIDesignerCodeConstants.ACTIVITYCLASSIFFALSE);
        //        ActivityModel iffalseActivity = new ActivityModel(iffalseMetadata, ComposerRenderer.UniqueCounter.ToString(CultureInfo.CurrentCulture));
        //        if (null != iffalseActivity)
        //        {
        //            falseBranchActivity.Children.Add(iffalseActivity);
        //            iffalseActivity.Parent = falseBranchActivity;
        //            iffalseActivity.DeleteBehavior = ActivityDeleteBehavior.DeleteChildren;
        //            iffalseActivity.CurrentParameterBindingVisibilty = this.ifElseModel.CurrentParameterBindingVisibilty;

        //            // Set the Visiblity as collapsed for If true
        //            ActivityModelVisibility falseActivityVisibility = new ActivityModelVisibility(Visibility.Visible, Visibility.Collapsed);
        //            iffalseActivity.VisibleOnUi = falseActivityVisibility;
        //        }

        //        falseBranchActivity.CurrentParameterBindingVisibilty = this.ifElseModel.CurrentParameterBindingVisibilty;

        //        ActivityModelVisibility actVisibility = new ActivityModelVisibility(Visibility.Collapsed, Visibility.Collapsed);
        //        falseBranchActivity.VisibleOnUi = actVisibility;

        //        falseBranchActivity.Parent = branchActivity;
        //        branchActivity.Children.Add(falseBranchActivity);
        //    }

        //    this.ifElseModel.Children.Add(branchActivity);
        //    branchActivity.Parent = this.ifElseModel;
        //}

        ///// <summary>
        ///// Intialises True Activity Model
        ///// </summary>
        ///// <param name="branchActivity"></param>
        //private void IntialiseTrueBranchActivityModel(ActivityModel branchActivity)
        //{
        //    ActivityMetadata trueBranchActivityMetadata = activityComposer.GetMetadata(UIDesignerCodeConstants.ACTIVITYCLASSSEQUENCE);
        //    ActivityModel trueBranchActivity = new ActivityModel(trueBranchActivityMetadata, ComposerRenderer.UniqueCounter.ToString(CultureInfo.CurrentCulture));

        //    if (null != trueBranchActivity)
        //    {
        //        ActivityMetadata iftrueMetadata = activityComposer.GetMetadata(UIDesignerCodeConstants.ACTIVITYCLASSIFTRUE);
        //        ActivityModel iftrueActivity = new ActivityModel(iftrueMetadata, ComposerRenderer.UniqueCounter.ToString(CultureInfo.CurrentCulture));
        //        if (null != iftrueActivity)
        //        {
        //            trueBranchActivity.Children.Add(iftrueActivity);
        //            iftrueActivity.Parent = trueBranchActivity;
        //            iftrueActivity.DeleteBehavior = ActivityDeleteBehavior.DeleteChildren;
        //            iftrueActivity.CurrentParameterBindingVisibilty = this.ifElseModel.CurrentParameterBindingVisibilty;

        //            // Set the Visiblity as collapsed for If true
        //            ActivityModelVisibility actVisibility = new ActivityModelVisibility(Visibility.Visible, Visibility.Collapsed);
        //            iftrueActivity.VisibleOnUi = actVisibility;
        //        }

        //        trueBranchActivity.CurrentParameterBindingVisibilty = this.ifElseModel.CurrentParameterBindingVisibilty;
        //        ActivityModelVisibility trueBranchVisibility = new ActivityModelVisibility(Visibility.Collapsed, Visibility.Collapsed);
        //        trueBranchActivity.VisibleOnUi = trueBranchVisibility;

        //        trueBranchActivity.Parent = branchActivity;
        //        branchActivity.Children.Add(trueBranchActivity);
        //    }
        //}

        ///// <summary>
        ///// Intialises Condition Activity Model
        ///// </summary>
        //private void IntialiseIfConditionActivityModel()
        //{
        //    ActivityMetadata conditionMetadata = this.activityComposer.GetMetadata(UIDesignerCodeConstants.ACTIVITYCLASSIFCONDITION);
        //    if (conditionMetadata != null)
        //    {
        //        ActivityModel childSequenceActivity = new ActivityModel(conditionMetadata, ComposerRenderer.UniqueCounter.ToString(CultureInfo.CurrentCulture));
        //        childSequenceActivity.Parent = this.ifElseModel;
        //        childSequenceActivity.DeleteBehavior = ActivityDeleteBehavior.DeleteChildren;
        //        childSequenceActivity.CurrentParameterBindingVisibilty = this.ifElseModel.CurrentParameterBindingVisibilty;
        //        // Set the Visiblity as collapsed for Condition
        //        ActivityModelVisibility actVisibility = new ActivityModelVisibility(Visibility.Visible, Visibility.Collapsed);
        //        childSequenceActivity.VisibleOnUi = actVisibility;
        //        this.ifElseModel.Children.Add(childSequenceActivity);
        //    }
        //}

        #endregion Commented

        #region ICompositeUiElement Members

        public ObservableCollection<ITridentUIElement> ChildElements
        {
            get
            {
                return this.childElements;
            }
        }

        public void AddChildElement(ITridentUIElement childElement)
        {
            #region Parameters check.

            if (null == childElement)
            {
                throw new ArgumentNullException("childElement");
            }

            #endregion Parameters check.

            this.childElements.Add(childElement);
            UIElement uiElem = childElement as UIElement;
            if (uiElem != null)
            {
                this.stkMainContentHolder.Children.Add(uiElem);
            }

            CompositeActivityElement childCompositeElement = childElement as CompositeActivityElement;
            if (childCompositeElement != null)
            {
                if (childElement.Model.ActivityClass.Equals(UIDesignerCodeConstants.ACTIVITYCLASSPARALLEL))
                {
                    childCompositeElement.Margin = new Thickness(5, 9.5, 10, 0);
                }
                else if (childElement.Model.ActivityClass.Equals(UIDesignerCodeConstants.ACTIVITYCLASSIFCONDITION))
                {
                    childCompositeElement.Margin = new Thickness(0, 10, 20, 0);
                    this.IntialiseConditionConnector((CompositeActivityModel)childElement.Model);
                    childCompositeElement.AddChildElement((ITridentUIElement)this.conditionConnector);
                }
            }
        }

        public void ArrangeBranches()
        {
            if (this.childElements.Count > 1)
            {
                CompositeActivityElement parallelElem = this.childElements[1] as CompositeActivityElement;
                if (parallelElem != null)
                {
                    for (int compositeCount = 0; compositeCount < parallelElem.ChildElements.Count; compositeCount++)
                    {
                        CompositeActivityElement compositeElem = parallelElem.ChildElements[compositeCount] as CompositeActivityElement;
                        if (compositeElem != null)
                        {
                            compositeElem.Margin = new Thickness(10, 5, 4, 5);
                        }
                    }
                }
            }
        }

        public void UpdateBranchPositions()
        {
            if (this.childElements.Count > 1)
            {
                CompositeActivityElement parallelElem = this.childElements[1] as CompositeActivityElement;
                if (parallelElem != null)
                {
                    parallelElem.UpdateBranchPositions();
                }
            }
        }

        private void IntialiseConditionConnector(CompositeActivityModel conditionModel)
        {
            this.conditionConnector = new ConditionConnector(conditionModel, this.DataTypes);
        }

        public void InsertChildElement(ITridentUIElement childElement, int indexToInsertAt)
        {
            #region Parameters check.

            if (null == childElement)
            {
                throw new ArgumentNullException("childElement");
            }

            if (0 > indexToInsertAt)
            {
                throw new ArgumentOutOfRangeException("indexToInsertAt");
            }

            #endregion Parameters check.

            this.childElements.Insert(indexToInsertAt, childElement);
            UIElement uiElem = childElement as UIElement;
            if (uiElem != null)
            {
                this.stkMainContentHolder.Children.Insert(indexToInsertAt + this.MetaUiElementsOffset, uiElem);
            }
        }

        public bool RemoveChildElement(ITridentUIElement childElement)
        {
            #region Parameters check.

            if (null == childElement)
            {
                throw new ArgumentNullException("childElement");
            }

            #endregion Parameters check.

            bool opStatus = false;
            if (this.childElements.Contains(childElement))
            {
                opStatus = this.childElements.Remove(childElement);
            }

            if (opStatus)
            {
                UIElement uiElem = childElement as UIElement;
                if (uiElem != null && this.stkMainContentHolder.Children.Contains(uiElem))
                {
                    this.stkMainContentHolder.Children.Remove(uiElem);
                }
            }

            return opStatus;
        }

        public void RemoveChildElementAt(int indexOfChild)
        {
            #region Parameters check.

            if (0 > indexOfChild || (this.childElements.Count - 1) < indexOfChild)
            {
                throw new ArgumentOutOfRangeException("indexOfChild");
            }

            if (0 > indexOfChild || (this.stkMainContentHolder.Children.Count - 1) < indexOfChild)
            {
                throw new ArgumentOutOfRangeException("indexOfChild");
            }

            #endregion Parameters check.

            this.childElements.RemoveAt(indexOfChild);
            this.stkMainContentHolder.Children.RemoveAt(indexOfChild + this.MetaUiElementsOffset);
        }

        #endregion

        public override void ApplySelectedStyle()
        {
            // Apply the background of the border.
            this.MainBorder.BorderBrush = Brushes.Orange;

            this.MainBorder.CornerRadius = new CornerRadius(5);
            this.MainBorder.VerticalAlignment = VerticalAlignment.Top;
        }

        public override void ApplyUnselectedStyle()
        {
            // Revert back all the changes made while selecting.
            this.MainBorder.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFC6D3D8"));
        }

        public override Point GetBindingStartPoint(UIElement relativeTo)
        {
            throw new System.NotImplementedException();
        }

        public override Point GetBindingEndpoint(UIElement relativeTo)
        {
            throw new System.NotImplementedException();
        }

        #region ICompositeUiElement Members

        public Panel MainContentHolder
        {
            get { return this.stkMainContentHolder; }
        }

        #endregion
    }
}